package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.mapper.CartInfoMapper;
import com.atguigu.gmall.cart.service.CartInfoAsyncService;
import com.atguigu.gmall.cart.service.CartInfoService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.common.exception.GmallException;
import com.atguigu.gmall.common.result.ResultCodeEnum;
import com.atguigu.gmall.common.util.AuthContextHolder;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author gsy
 * @date 2021年09月07日20:18
 * Description
 */
@Service
@Transactional
public class CartInfoServiceImpl implements CartInfoService {
    @Autowired
    private CartInfoMapper cartInfoMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private ProductFeignClient productFeignClient;

    @Autowired
    private CartInfoAsyncService cartInfoAsyncService;

    @Override
    public void addCart(Long skuId, Integer skuNum, String userId) {
        //判断redis缓存中是否存在该商品
        String cacheKeyCart = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        CartInfo cartInfo = (CartInfo) redisTemplate.opsForHash().get(cacheKeyCart, skuId.toString());
        if (cartInfo != null) {
            //购物车中该商品已经存在 更新数量即可
            cartInfo.setSkuNum(cartInfo.getSkuNum() + skuNum);
            //设置为选中状态
            cartInfo.setIsChecked(CartInfo.ISCHECK);
            // 方式一：cartInfoMapper.updateById(cartInfo);
            //方式二：
            //异步更新DB 导致reids的cartInfo无主键 只能更加用户id和库存id修改
            cartInfoAsyncService.updateAsync(cartInfo);

        } else {
            //商品第一次加入购物车 远程调用商品微服务查询商品信息
            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            //实时价格单独查询
            BigDecimal price = productFeignClient.getPrice(skuId);
            if (skuInfo != null && skuInfo.getId() != null) {
                cartInfo = new CartInfo();
                cartInfo.setUserId(userId);
                cartInfo.setSkuId(skuInfo.getId());
                //购物车中商品的价格
                cartInfo.setCartPrice(price);
                cartInfo.setSkuNum(skuNum);
                cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
                cartInfo.setSkuName(skuInfo.getSkuName());
                cartInfo.setIsChecked(CartInfo.ISCHECK);
                //加入购物车表
                //方式一:cartInfoMapper.insert(cartInfo);
                //方式二:
                cartInfoAsyncService.insertAysnc(cartInfo);

            } else {
                throw new GmallException(ResultCodeEnum.FAIL);
            }
        }
        //DB和redis双写 同步更新缓存
        //更新缓存的购物车信息
        redisTemplate.opsForHash().put(cacheKeyCart, skuId.toString(), cartInfo);
    }

    @Override
    public CartInfo findCartInfo(Long skuId) {
        ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = servletRequestAttributes.getRequest();
        String userId = AuthContextHolder.getUserId(request);
        if (StringUtils.isEmpty(userId)) {
            userId = AuthContextHolder.getUserTempId(request);
        }
        return cartInfoMapper.selectOne(new QueryWrapper<CartInfo>().eq("user_id",
                userId).eq("sku_id", skuId));
    }


    //查询用户id对应的购物车列表
    @Override
    public List<CartInfo> cartList(String userId, String userTempId) {
        //判断真实用户id是否存在
        if (!StringUtils.isEmpty(userId)) {
            //真实用户id存在 用户已登录
            if (!StringUtils.isEmpty(userTempId)) {
                //真实用户id和临时用户id都存在  真实用户对应的购物车和临时购物车大合并
                return mergeCartInfoList(userId, userTempId);
            } else {
                //只有真实用户id存在
                return getCartInfoList(userId);
            }
        } else {
            //真实用户不存在 用户未登录 用临时用户id
            //根据临时用户id查询购物车列表
            return getCartInfoList(userTempId);
        }

    }

    private List<CartInfo> getCartInfoList(String userId) {
        String cacheKeyCart = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cacheKeyCart);
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            for (CartInfo cartInfo : cartInfoList) {
                BigDecimal price = productFeignClient.getPrice(cartInfo.getSkuId());
                cartInfo.setSkuPrice(price);
            }
        }

        return cartInfoList;
    }

    //真实用户对应的购物车和临时购物车大合并
    private List<CartInfo> mergeCartInfoList(String userId, String userTempId) {
        //真实用户id对应的购物车集合
        String cacheKeyCart = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        List<CartInfo> cartInfoListByUserId = redisTemplate.opsForHash().values(cacheKeyCart);
        //临时用户id对应的购物车集合
        String cacheKeyCart1 = RedisConst.USER_KEY_PREFIX + userTempId + RedisConst.USER_CART_KEY_SUFFIX;
        List<CartInfo> cartInfoListByUserTempId = redisTemplate.opsForHash().values(cacheKeyCart1);
        //判断真实用户id对应的购物车是否为空
        if (!CollectionUtils.isEmpty(cartInfoListByUserId)) {
            //真实用户购物车有商品
            //判断临时用户id对应的购物车是否为空
            if (!CollectionUtils.isEmpty(cartInfoListByUserTempId)) {
                //临时购物车有商品 合并
                Map<Long, CartInfo> cartInfoMap = cartInfoListByUserId.stream()
                        .collect(Collectors.toMap(CartInfo::getSkuId, cartInfo -> cartInfo));
                for (CartInfo cartInfo : cartInfoListByUserTempId) {
                    //通过临时购物车的sku_id查询真实用户购物车是否有该商品
                    CartInfo cartInfo1 = cartInfoMap.get(cartInfo.getSkuId());
                    if (cartInfo1 != null) {
                        //真实用户购物车有此商品 更新用户购物车商品数量
                        QueryWrapper<CartInfo> cartInfoQueryWrapper = new QueryWrapper<>();
                        cartInfoQueryWrapper.eq("user_id", userId);
                        cartInfoQueryWrapper.eq("sku_id", cartInfo.getSkuId());
                        //更新用户购物车商品数量
                        cartInfo1.setSkuNum(cartInfo1.getSkuNum() + cartInfo.getSkuNum());
                        //设置选中
                        cartInfo1.setIsChecked(1);
                        cartInfoMapper.update(cartInfo1, cartInfoQueryWrapper);
                        //更新缓存中用户的商品的数量
                        redisTemplate.opsForHash().put(cacheKeyCart, cartInfo1.getSkuId().toString(), cartInfo1);

                    } else {
                        //真实用户购物车无此商品 将对应的商品用户临时id修改为真实用户id即可
                        QueryWrapper<CartInfo> cartInfoQueryWrapper = new QueryWrapper<>();
                        cartInfoQueryWrapper.eq("user_id", userTempId);
                        cartInfoQueryWrapper.eq("sku_id", cartInfo.getSkuId());
                        cartInfo.setUserId(userId);
                        //设置选中
                        cartInfo.setIsChecked(1);
                        //添加该商品信息到cartInfoMap集合
                        cartInfoMap.put(cartInfo.getSkuId(), cartInfo);
                        cartInfoMapper.update(cartInfo, cartInfoQueryWrapper);
                        //缓存中添加该商品的信息
                        redisTemplate.opsForHash().put(cacheKeyCart, cartInfo.getSkuId().toString(), cartInfo);
                    }
                }
                //删除缓存中临时用户的购物车
                redisTemplate.delete(cacheKeyCart1);

                return new ArrayList<>(cartInfoMap.values());

            } else {
                //临时购物车没有商品
                return cartInfoListByUserId;
            }

        } else {
            //真实用户购物车中无商品
            if (!CollectionUtils.isEmpty(cartInfoListByUserTempId)) {
                //临时购物车有商品 将对应的商品用户临时id修改为真实用户id即可
                //将对应的商品用户临时id修改为真实用户id
                cartInfoMapper.updateUserId(userId, userTempId);
                //将该临时购物车的商品存入到缓存redis中真实用户的购物车中
                Map<String, CartInfo> cartInfoMap = cartInfoListByUserTempId.stream().map(cartInfo -> {
                    cartInfo.setUserId(userId);
                    return cartInfo;
                }).collect(Collectors.toMap(CartInfo -> CartInfo.getSkuId().toString()
                        , cartInfo -> cartInfo));
                redisTemplate.opsForHash().putAll(cacheKeyCart, cartInfoMap);

                //删除缓存中临时用户的购物车
                redisTemplate.delete(cacheKeyCart1);

            }
            return cartInfoListByUserTempId;

        }
    }

    //复选框选中购物车
    @Override
    public void checkCart(Long skuId, Integer isChecked, String userId) {
        //修改DB选中状态
        CartInfo cartInfo = new CartInfo();
        cartInfo.setIsChecked(isChecked);
        cartInfoMapper.update(cartInfo,new QueryWrapper<CartInfo>().eq("user_id",userId).eq("sku_id",skuId));
        //修改缓存中选中的状态
        String cacheKeyCart = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        cartInfo = (CartInfo) redisTemplate.opsForHash().get(cacheKeyCart, skuId.toString());
        cartInfo.setIsChecked(isChecked);
        redisTemplate.opsForHash().put(cacheKeyCart,skuId.toString(),cartInfo);
    }

    //查询购物车选中的商品清单
    @Override
    public List<CartInfo> getCartCheckedList(String userId) {
        //查询缓存
        String cacheKeyCart = RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(cacheKeyCart);
        //过滤出选中的商品
        cartInfoList = cartInfoList.stream()
                .filter(cartInfo -> cartInfo.getIsChecked() == 1)
                .collect(Collectors.toList());
        for (CartInfo cartInfo : cartInfoList) {
            //远程调用商品微服务查询实时价格
            BigDecimal price = productFeignClient.getPrice(cartInfo.getSkuId());
            cartInfo.setSkuPrice(price);
        }
        return cartInfoList;

    }
}
